<?php declare(strict_types=1);

namespace Shopware\Core\Framework\Util;

use Shopware\Core\Framework\Log\Package;

#[Package('framework')]
class MemorySizeCalculator
{
    /**
     * This code is the same as the memory limit implementation of Symfony's consume message command. Since we want to
     * replicate the behaviour here we will be using the same implementation.
     *
     * See also:
     * https://github.com/symfony/messenger/blob/4319c25b76573cff46f112ee8cc83fffa4b97579/Command/ConsumeMessagesCommand.php#L243-L266
     */
    public static function convertToBytes(string $memoryLimit): int
    {
        $memoryLimit = strtolower($memoryLimit);
        $max = ltrim($memoryLimit, '+');
        if (str_starts_with($max, '0x')) {
            $max = \intval($max, 16);
        } elseif (str_starts_with($max, '0')) {
            $max = \intval($max, 8);
        } else {
            $max = (int) $max;
        }

        switch (substr(rtrim($memoryLimit, 'b'), -1)) {
            case 't': $max *= 1024;
                // no break
            case 'g': $max *= 1024;
                // no break
            case 'm': $max *= 1024;
                // no break
            case 'k': $max *= 1024;
        }

        return $max;
    }

    public static function formatToBytes(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];

        $bytes = max($bytes, 0);
        $pow = (int) floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, \count($units) - 1);

        $bytes /= (1 << (10 * $pow));

        return round($bytes, 2) . ' ' . $units[$pow];
    }

    public static function getMaxUploadSize(?int $maxSize = null): int
    {
        $values = [
            self::convertToBytes((string) ini_get('upload_max_filesize')),
            self::convertToBytes((string) ini_get('post_max_size')),
        ];

        if ($maxSize !== null) {
            $values[] = $maxSize;
        }

        /** @var non-empty-array{0?: int<1, max>, 1?: int<1, max>, 2?: int<1, max>} $limits */
        $limits = array_filter($values, static fn (int $value) => $value > 0);

        return min($limits);
    }
}
